package byx.container.annotation;

import byx.container.annotation.extension.core.*;
import byx.container.annotation.extension.impl.*;
import byx.container.annotation.util.ExtensionLoader;
import byx.container.annotation.util.PackageUtils;
import byx.container.core.ObjectFactory;
import byx.container.core.RegisterInfo;
import byx.container.core.SimpleContainer;

import java.util.ArrayList;
import java.util.List;

/**
 * 基于包扫描的容器
 */
public class PackageContainer extends SimpleContainer {
    private static final String FILE_EXTENSIONS = "META-INF/extensions.txt";
    private static final String FILE_EXPORTS = "META-INF/exports.txt";

    public PackageContainer() {
        this(StackWalker
                .getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                .getCallerClass());
    }

    public PackageContainer(Class<?> base) {
        this(base.getPackageName());
    }

    public PackageContainer(String packageName) {
        this(PackageUtils.getPackageClasses(packageName));
    }

    public PackageContainer(Class<?>[] classes) {
        this(List.of(classes));
    }

    public PackageContainer(List<Class<?>> classes) {
        // 加载插件
        registerExtensions();
        List<ClassProcessor> classProcessors = getObjects(ClassProcessor.class);
        List<ClassPostProcessor> classPostProcessors = getObjects(ClassPostProcessor.class);

        // 加载导出组件
        List<Class<?>> exportClasses = ExtensionLoader.getExtensionClasses(FILE_EXPORTS);
        List<Class<?>> classesToScan = new ArrayList<>(exportClasses);
        classesToScan.addAll(classes);

        // 扫描所有类
        processClass(classesToScan, classProcessors, classPostProcessors);
    }

    private void registerExtensions() {
        // 默认的参数解析器
        List<ParameterHandler> defaultParameterHandlers = List.of(
                new IdParameterHandler(),
                new CustomInjectParameterHandler(),
                new AnnotatedByParameterHandler(),
                new ValueParameterHandler(List.of(
                        new StringToString(),
                        new StringToInteger(),
                        new StringToDouble(),
                        new StringToBoolean()
                )),
                new ContainerParameterHandler(),
                new CollectionParameterHandler(),
                new DefaultParameterHandler()
        );
        ParameterResolver defaultParameterResolver = new ParameterResolver(this, defaultParameterHandlers);

        // 默认的ClassPostProcessor
        List<ClassPostProcessor> defaultClassPostProcessors = List.of(
                new InitProcessor(defaultParameterResolver),
                new WrapProcessor(),
                new SingletonProcessor()
        );

        // 默认的ClassScanner
        ClassScanner scanner = new ClassScanner(this, defaultParameterResolver);

        // 注册所有插件
        List<Class<?>> extensionClasses = ExtensionLoader.getExtensionClasses(FILE_EXTENSIONS);
        for (Class<?> c : extensionClasses) {
            ClassPostProcessorContext ctx = scanner.getTypeContext(c);
            postProcessClass(ctx, defaultClassPostProcessors);
        }
    }

    private void postProcessClass(ClassPostProcessorContext ctx, List<ClassPostProcessor> classPostProcessors) {
        AnnotationMetadata annotationMetadata = ctx.getAnnotationMetadata();
        RegisterInfo registerInfo = ctx.getRegisterInfo();
        String id = registerInfo.getId();
        int order = registerInfo.getOrder();
        Class<?> type = registerInfo.getType();
        ObjectFactory<?> factory = registerInfo.getFactory();
        for (ClassPostProcessor p : classPostProcessors) {
            factory = p.postProcess(
                    new ClassPostProcessorContext(registerInfo, this, annotationMetadata)
            );
            registerInfo = new RegisterInfo(id, type, order, factory);
        }
        factory = factory.guard();
        registerInfo = new RegisterInfo(id, type, order, factory);
        register(registerInfo);
    }

    private void processClass(List<Class<?>> classes, List<ClassProcessor> classProcessors, List<ClassPostProcessor> classPostProcessors) {
        for (ClassProcessor processor : classProcessors) {
            List<ClassPostProcessorContext> contexts = new ArrayList<>();
            for (Class<?> type : classes) {
                ClassProcessorContext ctx = new ClassProcessorContext(type, this);
                contexts.addAll(processor.process(ctx));
            }
            for (ClassPostProcessorContext ctx : contexts) {
                postProcessClass(ctx, classPostProcessors);
            }
        }
    }
}
